﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Text;
using System.IO;
using System.Web.Mvc.Html;
using System.Web.Routing;
using ASPMVCUtil.Helpers.Html.Grid;
using ASPMVCUtil.Helpers.Html.JQuery;
using ASPMVCUtil.Helpers.Ajax;
using ASPMVCUtil.Helpers;

namespace System.Web.Mvc.Html
{
    /// <summary>
    /// Clase que contiene extensiones del HtmlHelper para construir un grid 
    /// </summary>
    public static class GridHelpers
    {

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="helper"></param>
        /// <param name="columns"></param>
        /// <param name="list"></param>
        /// <param name="routeName"></param>
        /// <param name="pagerPosition"></param>
        /// <param name="maxHeight"></param>
        /// <param name="editable"></param>
        /// <param name="deletable"></param>
        /// <param name="selectable"></param>
        /// <param name="exportableToExcel"></param>
        /// <param name="exportToExcelUrl"></param>
        /// <param name="rowFormatter"></param>
        /// <returns></returns>
        public static MvcHtmlString Grid<TModel>(this HtmlHelper helper, IEnumerable<GridColumn<TModel>> columns, GridPagedList<TModel> list, 
            string routeName = "Default", GridPagerPosition pagerPosition = GridPagerPosition.Both, int maxHeight = 0,
            bool editable = true, bool deletable = true, bool selectable = true, bool exportableToExcel = true, 
            string exportToExcelUrl = null, GridRowFormatter<TModel> rowFormatter = null)
        {
            UrlHelper Url = new UrlHelper(helper.ViewContext.RequestContext);
            AjaxHelper Ajax = new AjaxHelper(helper.ViewContext, helper.ViewDataContainer);

            string id = list.GridParams.ID;
            string padreId = list.GridParams.FatherID;

            TagBuilder divGrid = new TagBuilder("div");
            divGrid.MergeAttribute("id", id);
            divGrid.MergeAttribute("class", "t-widget t-grid");

            bool paged = list.PageSize > 0;

            if (rowFormatter == null)
            {
                rowFormatter = new GridRowFormatter<TModel>();
            }

            if (exportableToExcel)
            {
                TagBuilder divExcel = new TagBuilder("div");
                divExcel.MergeAttribute("class", "t-grid-excel");

                TagBuilder a = new TagBuilder("a");
                a.MergeAttribute("class", "excel_exporter_icono");
                a.InnerHtml = GridResources.ExportToExcel;

                if (exportToExcelUrl == null)
                {
                    a.MergeAttribute("href", Url.Action(id + "Excel") + list.GridParams.QueryString.ToString());
                }
                else
                {
                    a.MergeAttribute("href", exportToExcelUrl);
                }
                divExcel.InnerHtml = a.ToString(TagRenderMode.Normal);

                divGrid.InnerHtml += divExcel.ToString(TagRenderMode.Normal);
            }

            if (pagerPosition == GridPagerPosition.Header || pagerPosition == GridPagerPosition.Both)
                divGrid.InnerHtml += GridPaginador<TModel>(helper, id, list, "encabezado", paged, routeName);

            divGrid.InnerHtml += BuildHeader<TModel>(helper, Url, id, columns, list.GridParams, editable, deletable, routeName, maxHeight);

            divGrid.InnerHtml += GridContenido<TModel>(helper, Url, Ajax, id, padreId, columns, list, editable, deletable, selectable, 
                maxHeight, rowFormatter, pagerPosition);

            if (pagerPosition == GridPagerPosition.Footer || pagerPosition == GridPagerPosition.Both)
                divGrid.InnerHtml += GridPie<TModel>(helper, id, list, paged, routeName);

            return MvcHtmlString.Create(GridMessages(id) + JS.outl() + divGrid.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="helper"></param>
        /// <param name="Url"></param>
        /// <param name="gridId"></param>
        /// <param name="columnas"></param>
        /// <param name="parametros"></param>
        /// <param name="editable"></param>
        /// <param name="eliminable"></param>
        /// <param name="ruta"></param>
        /// <param name="maxHeight"></param>
        /// <returns></returns>
        public static MvcHtmlString BuildHeader<TModel>(this HtmlHelper helper, UrlHelper Url, string gridId, IEnumerable<GridColumn<TModel>> columnas,
            GridParams parametros, bool editable, bool eliminable, string ruta, int maxHeight)
        {
            TagBuilder divHeader = new TagBuilder("div");
            divHeader.MergeAttribute("class", "t-grid-header" + ((maxHeight > 0) ? " t-grid-header-scrolled" : ""));

            TagBuilder divHeaderWrap = new TagBuilder("div");
            divHeaderWrap.MergeAttribute("class", "t-grid-header-wrap");

            TagBuilder table = new TagBuilder("table");
            table.MergeAttribute("cellspacing", "0");

            TagBuilder colgroup = construirColgroup(columnas, editable, eliminable);

            TagBuilder thead = new TagBuilder("thead");
            TagBuilder tr = new TagBuilder("tr");
            foreach (var columna in columnas)
            {
                if(columna.Visible)
                    tr.InnerHtml += HeaderColumn(Url, gridId, columna, parametros, ruta);
            }
            if (editable || eliminable)
                tr.InnerHtml += ActionsColumnHeader();
            thead.InnerHtml = tr.ToString(TagRenderMode.Normal);

            table.InnerHtml = colgroup.ToString(TagRenderMode.Normal) + thead.ToString(TagRenderMode.Normal);
            divHeaderWrap.InnerHtml = table.ToString(TagRenderMode.Normal);
            divHeader.InnerHtml = divHeaderWrap.ToString(TagRenderMode.Normal);
            return MvcHtmlString.Create(divHeader.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// Construye un elemento (TH) del encabezado del grid
        /// </summary>
        /// <typeparam name="T">Tipo de dato del grid</typeparam>
        /// <param name="Url">UrlHelper</param>
        /// <param name="column">Columna</param>
        /// <param name="gridParams">Parámetros del grid</param>
        /// <param name="route">Ruta para ser propagada</param>
        /// <returns>Elemento th que contiene la columna del encabezado</returns>
        private static MvcHtmlString HeaderColumn<TModel>(UrlHelper Url, string gridId, GridColumn<TModel> column, GridParams gridParams, string route)
        {
            TagBuilder th = new TagBuilder("th");
            th.MergeAttribute("class", "t-header");
            th.MergeAttribute("scope", "col");
            TagBuilder a = new TagBuilder("a");
            if (column.AdditionalCSSClasses != null)
                a.MergeAttribute("class", "t-link" + spaceSeparated(column.AdditionalCSSClasses));
            else
                a.MergeAttribute("class", "t-link");
            if (column.Ordenable)
            {
                var ordenEsperado = column.PropertyName;
                if (gridParams.OrderField != null && gridParams.OrderField.Equals(ordenEsperado))
                {
                    if (gridParams.OrderDirection.Equals(GridOrderDirection.asc.ToString()))
                        a.MergeAttribute("href", getOrderRoute(Url, gridId, gridParams, column, GridOrderDirection.desc.ToString(), route));
                    else
                        a.MergeAttribute("href", getOrderRoute(Url, gridId, gridParams, column, null, route));
                    TagBuilder spanOrderIcon = new TagBuilder("span");
                    var flecha = "down";
                    if (gridParams.OrderDirection.Equals(GridOrderDirection.desc.ToString()))
                        flecha = "up";
                    spanOrderIcon.MergeAttribute("class", "t-icon t-arrow-" + flecha);
                    a.InnerHtml = column.Header + spanOrderIcon.ToString(TagRenderMode.SelfClosing);
                }
                else
                {
                    a.MergeAttribute("href", getOrderRoute(Url, gridId, gridParams, column, GridOrderDirection.asc.ToString(), route));
                    a.InnerHtml = column.Header;
                }
                th.InnerHtml = a.ToString(TagRenderMode.Normal);
            }
            else
            {
                a.MergeAttribute("href", "#");
                a.MergeAttribute("style", "cursor: default");
                a.InnerHtml = column.Header;

                th.InnerHtml = a.ToString(TagRenderMode.Normal);
            }
            return MvcHtmlString.Create(th.ToString(TagRenderMode.Normal));
        }

        private static string spaceSeparated(string[] array)
        {
            string spaceSeparated = "";
            foreach (string item in array)
            {
                spaceSeparated += " " + item;
            }
            return spaceSeparated;
        }

        private static string getOrderRoute<TModel>(UrlHelper Url, string gridId, GridParams parametros, GridColumn<TModel> columna, string direccion, string ruta)
        {
            var queryString = parametros.QueryString.Clone();
            if (direccion == null)
            {
                try
                {
                    queryString.Remove(GridParams.orderByParamString(gridId));
                }
                catch { }
            }
            else
            {
                var orden = columna.PropertyName;
                queryString[GridParams.orderByParamString(gridId)] = orden + "-" + direccion;
            }
            return Url.RouteUrl(ruta) + queryString.ToString();
        }

        /// <summary>
        /// Construye un elemento (TH) del encabezado del grid para la columna de acciones
        /// </summary>
        private static MvcHtmlString ActionsColumnHeader()
        {
            TagBuilder th = new TagBuilder("th");
            th.MergeAttribute("class", "t-header");
            th.MergeAttribute("scope", "col");

            TagBuilder a = new TagBuilder("a");
            a.MergeAttribute("href", "#");
            a.MergeAttribute("style", "cursor: default");
            a.MergeAttribute("class", "t-link");
            a.InnerHtml = GridResources.ActionsHeaderText;

            th.InnerHtml = a.ToString(TagRenderMode.Normal);
            return MvcHtmlString.Create(th.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="helper"></param>
        /// <param name="Url"></param>
        /// <param name="Ajax"></param>
        /// <param name="gridId"></param>
        /// <param name="padreId"></param>
        /// <param name="columns"></param>
        /// <param name="listado"></param>
        /// <param name="editable"></param>
        /// <param name="eliminable"></param>
        /// <param name="seleccionable"></param>
        /// <param name="maxHeight"></param>
        /// <param name="rowFormatter"></param>
        /// <param name="?"></param>
        /// <param name="posicionPaginador"></param>
        /// <returns></returns>
        public static MvcHtmlString GridContenido<TModel>(this HtmlHelper helper, UrlHelper Url, AjaxHelper Ajax, string gridId, string padreId,
            IEnumerable<GridColumn<TModel>> columns, GridPagedList<TModel> listado, bool editable, bool eliminable,
            bool seleccionable, int maxHeight, GridRowFormatter<TModel> rowFormatter, GridPagerPosition posicionPaginador)
        {
            TagBuilder divContent = new TagBuilder("div");
            divContent.MergeAttribute("class", "t-grid-content");
            if(maxHeight > 0)
                divContent.MergeAttribute("style", "max-height: " + maxHeight + "px; overflow-y:scroll;");

            TagBuilder table = new TagBuilder("table");
            table.MergeAttribute("cellspacing", "0");
            table.MergeAttribute("id", gridId + "-insertar-fila");

            TagBuilder colgroup = construirColgroup(columns, editable, eliminable);

            TagBuilder tbody = new TagBuilder("tbody");

            var i = 0;

            //Recorro el listado
            foreach (var record in listado)
            {
                List<KeyMember> keyMembers = new List<KeyMember>(); 

                TagBuilder tr = new TagBuilder("tr");

                foreach (string keyMemberName in listado.KeyMembersNames)
                {
                    //Obtengo el identificador del registro
                    var propiedad = record.GetType().GetProperty(keyMemberName);
                    if (propiedad == null)
                        throw new ArgumentException(string.Format(GridResources.InvalidInput1, keyMemberName));
                    if (propiedad.CanRead)
                    {
                        var valorId = propiedad.GetValue(record, null);
                        if (valorId != null)
                        {
                            keyMembers.Add(new KeyMember() { PropertyName = keyMemberName, Value = valorId.ToString() });
                        }
                        else
                            throw new ArgumentException(string.Format(GridResources.InvalidInput2, keyMemberName));
                    }
                    else
                        throw new ArgumentException(string.Format(GridResources.InvalidInput3, keyMemberName));
                }

                Key key = new Key(keyMembers);

                tr.MergeAttribute("id", gridId + "-row-" + key.KeyString);

                //Pongo los estilos correspondientes de la fila
                tr.MergeAttribute("class", "t-grid-tr"
                    + ((i % 2 != 0) ? " t-alt" : "")
                    + ((seleccionable) ? " grid-tr-seleccionable" : "")
                    + ((key.KeyString.Equals(listado.GridParams.SelectedRowID)) ? " grid-tr-seleccionada" : "")
                    + " " + rowFormatter.Formatear(record));
                i++;

                RouteValueDictionary routeValues = new RouteValueDictionary();
                routeValues.Add("id", key.KeyString);

                //Recorro las columnas
                foreach (var column in columns)
                {
                    if (column.Visible)
                    {
                        TagBuilder td = new TagBuilder("td");
                        //TODO: el id de la celda no puede tener el PropertyName ya que genera repetidos
                        td.MergeAttribute("id", gridId + "-row-" + key.KeyString + "-" + column.PropertyName);
                       
                        if (column.AdditionalCSSClasses != null)
                            td.MergeAttribute("class", spaceSeparated(column.AdditionalCSSClasses));

                        //Obtengo la propiedad de la columna para el registro
                        string valor = column.getValue(record, routeValues, key);
                        td.InnerHtml = valor;

                        //Pongo comportamiento de selección
                        if (seleccionable)
                        {
                            var queryString = listado.GridParams.QueryString.Clone();
                            queryString[GridParams.iDParamString(gridId)] = key.KeyString;
                            //TODO: revisar por qué esto
                            if (listado.GridParams.FatherID != null)
                                queryString[GridParams.iDParamString(gridId)] = key.KeyString;
                            //td.MergeAttribute("onclick", "window.location.href = '" + Url.Action("Index") + queryString.ToString() + "'");
                            td.MergeAttribute("onclick", "window.location.href = '" + Url.RequestContext.HttpContext.Request.FilePath + queryString.ToString() + "'");
                        }

                        tr.InnerHtml += td.ToString(TagRenderMode.Normal);
                    }
                    else
                    {
                        column.getValue(record, routeValues, key);
                    }
                }

                TagBuilder tdAcciones = new TagBuilder("td");
                tdAcciones.MergeAttribute("style", "text-align: center");

                if (editable)
                {
                    MvcHtmlString editar = ActionLink.ActionLinkImage(helper, Url, Url.Content("~/Images/ASPMVCUtil/Grid/edit.png"), GridResources.Edit,
                        "Edit" + gridId, new { id = key.KeyString }, new { style = "border: 0px; margin: 2px;" });

                    /*MvcHtmlString editarAjax = ActionLinkAjax.ActionLinkImagen(Ajax, Url.Content("~/Images/ASPMVCUtil/Grid/edit.png"), GridResources.Edit,
                        "_Edit", new { id = ID }, new AjaxOptions
                        {
                            OnBegin = "function(){ return onBegin(this); }",
                            OnComplete = "function(){ return onCompleteEditar(this); }",
                            OnSuccess = "onSuccessEditar" + gridId,
                            OnFailure = "onFailureEditar" + gridId,
                            HttpMethod = "GET"
                        }, new { style = "border: 0px; margin: 2px;" });*/

                    tdAcciones.InnerHtml += editar.ToString()/*editarAjax.ToString()*/;
                }

                if(eliminable) 
                {
                    if(padreId != null) {
                        routeValues.Add("pID", listado.GridParams.FatherID);
                    }
                    /*Commented because jquery.unobtrusive-ajax.js problem
                    MvcHtmlString eliminar = ActionLinkAjax.ActionLinkImagen(Ajax, Url.Content("~/Images/ASPMVCUtil/Grid/delete.png"), GridResources.Delete,
                        "_Delete" + gridId, routeValues, new AjaxOptions
                        {
                            OnBegin = "function(){ return onBegin(this); }",
                            OnComplete = "function(){ return onCompleteDelete" + gridId + "(this); }",
                            OnSuccess = "onSuccessDelete" + gridId,
                            OnFailure = "onFailureDelete" + gridId,
                            Confirm = string.Format(GridResources.DeleteConformation, record.ToString()),
                            HttpMethod = "DELETE"
                        }, new { style = "border: 0px; margin: 2px;" });*/
                    MvcHtmlString eliminar = Images.Image(helper, Url.Content("~/Images/ASPMVCUtil/Grid/delete.png"), GridResources.Delete,
                        new { @class = "delete-icon-" + gridId, style = "border: 0; cursor: pointer; margin: 2px;",
                              url = Url.Action("_Delete" + gridId, routeValues), tostring = record.ToString() });
                    tdAcciones.InnerHtml += eliminar.ToString();
                }
                if(eliminable || editable)
                    tr.InnerHtml += tdAcciones.ToString(TagRenderMode.Normal);
                tbody.InnerHtml += tr.ToString(TagRenderMode.Normal);
            }

            table.InnerHtml = colgroup.ToString(TagRenderMode.Normal) + tbody.ToString(TagRenderMode.Normal);

            //Added because jquery.unobtrusive-ajax.js problem
            TagBuilder script = new TagBuilder("script");
            var s = JS.outl();
            s += JS.outl("$(function () {");
            s += JS.outl("  $('.delete-icon-" + gridId + "').click(function (event) {");
            s += JS.outl("      var img = $(this);");
            s += JS.outl("      var r = confirm('" + GridResources.DeleteConfirmation + "'.format(img.attr('tostring')));");
            s += JS.outl("      if(r == true) {");
            s += JS.outl("          var id = $(this).parent().parent().attr('id').replace('" + gridId + "-row-', '');");
            s += JS.outl("          img.attr('src', '" + Url.Content("~/Images/ASPMVCUtil/loading.gif") + "');");
            s += JS.outl("          var request = $.ajax({");
            s += JS.outl("              url: img.attr('url'),");
            s += JS.outl("              type: 'DELETE',");
            s += JS.outl("              dataType: 'json'");
            s += JS.outl("          });");
            s += JS.outl("          request.always(function () {");
            s += JS.outl("              img.attr('src', '" + Url.Content("~/Images/ASPMVCUtil/Grid/delete.png") + "');");
            s += JS.outl("          });");
            s += JS.outl("          request.fail(function (jqXHR, textStatus) {");
            s += JS.outl("              ponerMensaje10segundos('" + gridId + "', textStatus + ': ' + jqXHR.responseText, true);");
            s += JS.outl("          });");
            s += JS.outl("          request.done(function (data) {");
            s += JS.outl("              var result = data.Data;");
            s += JS.outl("              // Update the page elements");

            TagBuilder tag = new TagBuilder("tr");
            tag.MergeAttribute("id", gridId + "-row-");

            s += JS.outl("              if(data.Result == 1) {");
            s += JQueryHelper.fadeOut("$('#" + tag.Attributes["id"] + "' + result.ID)", VelocidadEfecto.slow);
            s += jsMostrarMensaje(gridId, "result.Message");
            if (posicionPaginador == GridPagerPosition.Footer || posicionPaginador == GridPagerPosition.Both)
                s += JS.outl("                  actualizarNumRegistros" + gridId + "('pie');");
            if (posicionPaginador == GridPagerPosition.Header || posicionPaginador == GridPagerPosition.Both)
                s += JS.outl("                  actualizarNumRegistros" + gridId + "('encabezado');");
            s += JS.outl("              }");
            s += JS.outl("              else {");
            s += jsMostrarMensaje(gridId, "result.Message", true);
            s += JS.outl("              }");
            s += JS.outl("          });");
            s += JS.outl("      }");
            s += JS.outl("  });");
            s += JS.outl("});");
            
            s += JS.outl("function actualizarNumRegistros" + gridId + "(sufijo) {");
            s += JS.outl("        var regTotal = $('#" + gridId + "-registros-total-' + sufijo);");
            s += JS.outl("        var regFin = $('#" + gridId + "-registros-fin-' + sufijo);");
            s += JS.outl("        var regInicio = $('#" + gridId + "-registros-inicio-' + sufijo);");
            s += JS.outl("        var rTotal = parseInt(regTotal.text(), 10);");
            s += JS.outl("        var rFin = parseInt(regFin.text(), 10);");
            s += JS.outl();
            s += JS.outl("        if (rFin > rTotal - 1)");
            s += JQueryHelper.fadeOut("regFin", VelocidadEfecto.slow);
            s += JS.outl("        if(rTotal - 1 == 0)");
            s += JQueryHelper.fadeOut("regInicio", VelocidadEfecto.slow);
            s += JS.outl("        regTotal.fadeOut('slow', function () {");
            s += JS.outl();
            s += JS.outl("            regTotal.text(rTotal - 1);");
            s += JS.outl("            if (rFin > rTotal - 1) {");
            s += JS.outl("                regFin.text(rTotal - 1);");
            s += JQueryHelper.fadeIn("regFin", VelocidadEfecto.slow);
            s += JS.outl("            }");
            s += JS.outl("            if (rTotal - 1 == 0) {");
            s += JS.outl("                regInicio.text(0);");
            s += JQueryHelper.fadeIn("regInicio", VelocidadEfecto.slow);
            s += JS.outl("            }");
            s += JQueryHelper.fadeIn("regTotal", VelocidadEfecto.slow);
            s += JS.outl("        });");
            s += JS.outl("}");

            script.InnerHtml = s;
            divContent.InnerHtml = table.ToString(TagRenderMode.Normal) + JS.outl() + script.ToString(TagRenderMode.Normal);
            return MvcHtmlString.Create(divContent.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// Construye pie del grid
        /// </summary>
        /// <typeparam name="T">Tipo de dato del grid</typeparam>
        /// <param name="helper">HtmlHelper</param>
        /// <param name="gridId">Id del Grid, debe ser único en su contexto</param>
        /// <param name="listado">Lista paginada</param>
        /// <returns>MvcHtmlString</returns>
        public static MvcHtmlString GridPaginador<TModel>(this HtmlHelper helper, string gridId, GridPagedList<TModel> listado, string sufijo, bool paginada, string ruta)
        {
            UrlHelper Url = new UrlHelper(helper.ViewContext.RequestContext);

            TagBuilder divPagerWrapper = new TagBuilder("div");
            divPagerWrapper.MergeAttribute("class", "t-pager-wrapper");

            if (paginada)
            {

                TagBuilder divPageReset = new TagBuilder("div");
                divPageReset.MergeAttribute("class", "t-pager t-reset");

                TagBuilder aPrimera = construirArrowPie(Url, listado.HayPaginaAnterior, GridResources.PagerFirst, "first", 1, gridId, listado.GridParams, ruta);
                TagBuilder aAnterior = construirArrowPie(Url, listado.HayPaginaAnterior, GridResources.PagerPrevious, "prev", listado.CurrentPage - 1, gridId, listado.GridParams, ruta);

                TagBuilder spanPagina = new TagBuilder("span");
                spanPagina.InnerHtml = listado.GridParams.CurrentPage + " de " + ((listado.TotalPages > 0) ? listado.TotalPages : 1);

                TagBuilder aSiguiente = construirArrowPie(Url, listado.HayPaginaSiguiente, GridResources.PagerNext, "next", listado.CurrentPage + 1, gridId, listado.GridParams, ruta);
                TagBuilder aUltima = construirArrowPie(Url, listado.HayPaginaSiguiente, GridResources.PagerLast, "last", listado.TotalPages, gridId, listado.GridParams, ruta);

                divPageReset.InnerHtml = aPrimera.ToString(TagRenderMode.Normal) + aAnterior.ToString(TagRenderMode.Normal)
                    + spanPagina.ToString(TagRenderMode.Normal) + aSiguiente.ToString(TagRenderMode.Normal) + aUltima.ToString(TagRenderMode.Normal);

                TagBuilder divStatusText = new TagBuilder("div");
                divStatusText.MergeAttribute("class", "t-status-text");

                TagBuilder spanRegistrosInicio = new TagBuilder("span");
                spanRegistrosInicio.MergeAttribute("id", gridId + "-registros-inicio-" + sufijo);
                spanRegistrosInicio.InnerHtml = (listado.Total > 0) ? listado.RegistroInicio.ToString() : "0";

                TagBuilder spanRegistrosFin = new TagBuilder("span");
                spanRegistrosFin.MergeAttribute("id", gridId + "-registros-fin-" + sufijo);
                spanRegistrosFin.InnerHtml = listado.RegistroFin.ToString();

                TagBuilder spanRegistrosTotal = new TagBuilder("span");
                spanRegistrosTotal.MergeAttribute("id", gridId + "-registros-total-" + sufijo);
                spanRegistrosTotal.InnerHtml = listado.Total.ToString();

                divStatusText.InnerHtml = string.Format(GridResources.PagerLegend, spanRegistrosInicio.ToString(TagRenderMode.Normal), spanRegistrosFin.ToString(TagRenderMode.Normal),
                    spanRegistrosTotal.ToString(TagRenderMode.Normal));

                divPagerWrapper.InnerHtml = divPageReset.ToString(TagRenderMode.Normal) + divStatusText.ToString(TagRenderMode.Normal);
            }
            else
            {
                TagBuilder divStatusText = new TagBuilder("div");
                divStatusText.MergeAttribute("class", "t-status-text");

                TagBuilder spanRegistrosTotal = new TagBuilder("span");
                spanRegistrosTotal.MergeAttribute("id", gridId + "-registros-total-" + sufijo);
                spanRegistrosTotal.InnerHtml = listado.Total.ToString();

                divStatusText.InnerHtml = string.Format(GridResources.NoPagerLegend, spanRegistrosTotal.ToString(TagRenderMode.Normal));

                divPagerWrapper.InnerHtml = divStatusText.ToString(TagRenderMode.Normal);
            }
            return MvcHtmlString.Create(divPagerWrapper.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// Construye la estructura del pie del grid
        /// </summary>
        /// <typeparam name="T">Tipo de dato del grid</typeparam>
        /// <param name="helper">HtmlHelper</param>
        /// <param name="gridId">Id del Grid, debe ser único en su contexto</param>
        /// <returns></returns>
        public static MvcHtmlString GridPie<TModel>(this HtmlHelper helper, string gridId, GridPagedList<TModel> listado, bool paginada, string ruta)
        {
            TagBuilder divFooter = new TagBuilder("div");
            divFooter.MergeAttribute("class", "t-grid-footer");
            MvcHtmlString paginador = GridPaginador<TModel>(helper, gridId, listado, "pie", paginada, ruta);
            divFooter.InnerHtml = paginador.ToString();
            return MvcHtmlString.Create(divFooter.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="gridId">Id del grid</param>
        /// <param name="mensaje">Mensaje a poner, debe incluir las marcas de unicio y fin de cadena ('')</param>
        /// <param name="failure">Indica si es un mensaje de error</param>
        /// <returns></returns>
        private static string jsMostrarMensaje(string gridId, string mensaje, bool failure = false)
        {
            return JS.outl("ponerMensaje10segundos('" + gridId + "', " + mensaje + ", " + ((failure) ? "true" : "false") + ");");
        }

        private static TagBuilder construirColgroup<TModel>(IEnumerable<GridColumn<TModel>> columnas, bool editable, bool eliminable)
        {
            TagBuilder table = new TagBuilder("table");
            table.MergeAttribute("cellspacing", "0");

            TagBuilder colgroup = new TagBuilder("colgroup");
            foreach (var columna in columnas)
            {
                if (columna.Visible)
                {
                    TagBuilder col = new TagBuilder("col");
                    if (!columna.Width.Equals("*"))
                        col.MergeAttribute("style", "width: " + columna.Width + "px");
                    colgroup.InnerHtml += col.ToString(TagRenderMode.SelfClosing);
                }
            }

            if (editable || eliminable)
            {
                TagBuilder colAcciones = new TagBuilder("col");
                colAcciones.MergeAttribute("style", "width: 85px");
                colgroup.InnerHtml += colAcciones.ToString(TagRenderMode.SelfClosing);
            }
            return colgroup;
        }

        private static TagBuilder construirArrowPie(UrlHelper Url, bool habilitado, string texto, string clase, int pagina, string gridId, GridParams parametros, string ruta)
        {
            TagBuilder a = new TagBuilder("a");
            if (habilitado)
            {
                a.MergeAttribute("class", "t-link");
                var queryString = parametros.QueryString.Clone();
                queryString[GridParams.fatherParamString(gridId)] = pagina + "";
                a.MergeAttribute("href", Url.RouteUrl(ruta) + queryString.ToString());
            }
            else
            {
                a.MergeAttribute("class", "t-link t-state-disabled");
            }
            TagBuilder spanUltima = new TagBuilder("span");
            spanUltima.MergeAttribute("class", "t-icon t-arrow-" + clase);
            spanUltima.InnerHtml = texto;
            a.InnerHtml = spanUltima.ToString(TagRenderMode.Normal);
            return a;
        }

        private static string GridMessages(string gridId)
        {
            TagBuilder message = new TagBuilder("div");
            message.MergeAttribute("id", gridId + "-message");

            TagBuilder messageFailure = new TagBuilder("div");
            messageFailure.MergeAttribute("id", gridId + "-message-failure");

            return message.ToString(TagRenderMode.Normal) + JS.outl() + messageFailure.ToString(TagRenderMode.Normal);
        }
    }
}